package tcc.wa.service;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.BasicResponseHandler;
import org.apache.http.impl.client.DefaultHttpClient;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import tcc.wa.model.HourlyWeatherForecast;
import tcc.wa.model.Location;
import tcc.wa.persistence.dao.HourlyWeatherForecastDAO;
import android.content.Context;
import android.util.Log;

/**
 * Service class for HourlyWeatherForecasts.
 */
public class HourlyWeatherForecastService {

	private final String TAG = "HourlyWeatherForecastService";
	
	private final String updateHourlyWeatherForecastUrl = "http://api.wunderground.com/api/d09917472096c37e/hourly/q/{latitude},{longitude}.json";
	
	private final HourlyWeatherForecastDAO hourlyWeatherForecastDAO;
	
	public HourlyWeatherForecastService(Context context) {
		hourlyWeatherForecastDAO = new HourlyWeatherForecastDAO(context);
	}
	
	/**
	 * Updates the HourlyWeatherForecasts.
	 *
	 * @param location the device location
	 * @return a list containing the HourlyWeatherForecast for the next 24 hours
	 * @throws ClientProtocolException the client protocol exception
	 * @throws IOException Signals that an I/O exception has occurred
	 * @throws JSONException in case it fails to parse the server response
	 */
	public List<HourlyWeatherForecast> update(Location location) throws ClientProtocolException, IOException, JSONException {
		Log.i(TAG, "Updating hourly weather forecasts...");
		String requestString = updateHourlyWeatherForecastUrl.replace("{latitude}", String.valueOf(location.getGeographicCoordinate().getLatitude()));
		requestString = requestString.replace("{longitude}", String.valueOf(location.getGeographicCoordinate().getLongitude()));
		HttpClient httpClient = new DefaultHttpClient();
		HttpGet request = new HttpGet(requestString);
		ResponseHandler<String> handler = new BasicResponseHandler();
		String result = httpClient.execute(request, handler);
		httpClient.getConnectionManager().shutdown();
		JSONObject jsonObject = new JSONObject(result);
		JSONArray forecastHours = jsonObject.getJSONArray("hourly_forecast");
		List<HourlyWeatherForecast> hourlyForecasts = buildHourlyWeatherForecastsFrom(forecastHours, location);
		Log.i(TAG, "Successfully obtained new daily weather forecasts. Count: " + hourlyForecasts.size());
		return hourlyForecasts;
	}
	
	/**
	 * Saves a list of HourlyWeatherForecasts.
	 *
	 * @param hourlyForecasts a list of hourly forecasts
	 */
	public void save(List<HourlyWeatherForecast> hourlyForecasts) {
		Log.i(TAG, "Saving current hourly forecasts...");
		hourlyWeatherForecastDAO.save(hourlyForecasts);
		Log.i(TAG, "Successfully saved hourly forecasts.");
	}
	
	/**
	 * Finds the last saved HourlyWeatherForecasts.
	 *
	 * @return the last saved HourlyWeatherForecasts
	 */
	public List<HourlyWeatherForecast> findLast() {
		Log.i(TAG, "Finding last hourly weather forecasts...");
		List<HourlyWeatherForecast> hourlyForecasts = hourlyWeatherForecastDAO.findLast();
		if (hourlyForecasts != null && hourlyForecasts.size() > 0)
			Log.i(TAG, "Found last hourly weather forecasts.");
		else
			Log.i(TAG, "Couldn't find last hourly weather forecasts.");
		return hourlyForecasts;
	}
	
	/**
	 * Builds the hourly weather forecasts from the web service response.
	 *
	 * @param forecastHours a JSONObject containing the raw HourlyWeatherForecasts
	 * @param location the device location
	 * @return a list containing the HourlyWeatherForecasts for the next 24 hours
	 * @throws JSONException in case it fails to parse the server response
	 */
	private List<HourlyWeatherForecast> buildHourlyWeatherForecastsFrom(JSONArray forecastHours, Location location) throws JSONException {
		ArrayList<HourlyWeatherForecast> forecasts = new ArrayList<HourlyWeatherForecast>();
		int index = 0;
		while (index < 24) {
			JSONObject currentHour = forecastHours.getJSONObject(index);
			HourlyWeatherForecast forecast = new HourlyWeatherForecast();
			Date date = new Date();
			date.setDate(currentHour.getJSONObject("FCTTIME").getInt("mday"));
			date.setMonth(currentHour.getJSONObject("FCTTIME").getInt("mon") - 1);
			date.setYear(currentHour.getJSONObject("FCTTIME").getInt("year") - 1900);
			date.setHours(currentHour.getJSONObject("FCTTIME").getInt("hour"));
			date.setMinutes(currentHour.getJSONObject("FCTTIME").getInt("min"));
			date.setSeconds(currentHour.getJSONObject("FCTTIME").getInt("sec"));
			double temperature = currentHour.getJSONObject("temp").getDouble("metric");
			double relativeHumidity = currentHour.getDouble("humidity");
			double precipitation = !currentHour.getJSONObject("qpf").getString("metric").equals("") ? currentHour.getJSONObject("qpf").getDouble("metric") : 0f;
			forecast.setDate(date);
			forecast.setLocation(location);
			forecast.setTemperature(temperature);
			forecast.setRelativeHumidity(relativeHumidity);
			forecast.setPrecipitation(precipitation);
			forecasts.add(forecast);
			index++;
		}
		return forecasts;
	}
}
